package com.wanyang.aliyun.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.green.model.v20180509.ImageSyncScanRequest;
import com.aliyuncs.green.model.v20180509.TextScanRequest;
import com.aliyuncs.green.model.v20180509.VideoAsyncScanRequest;
import com.aliyuncs.green.model.v20180509.VideoAsyncScanResultsRequest;
import com.aliyuncs.http.FormatType;
import com.aliyuncs.http.HttpResponse;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.wanyang.aliyun.AfterScan;
import com.wanyang.aliyun.configure.AccessProperties;
import com.wanyang.aliyun.configure.ContentScanProperties;
import com.wanyang.aliyun.dto.ImageTaskDTO;
import com.wanyang.aliyun.dto.TextTaskDTO;
import com.wanyang.aliyun.dto.VideoTaskDTO;
import com.wanyang.aliyun.vo.AsyncScanResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Service
@Slf4j
public class AliyunContentScanServiceImpl implements AliyunContentScanService {

    @Autowired
    private AccessProperties accessProperties;

    @Autowired
    private ContentScanProperties contentScanProperties;

    @Override
    public void syncTextScan(List<TextTaskDTO> tasks, AfterScan afterScan) {
        Assert.notNull(afterScan, "afterScan cannot be null");
        Assert.isTrue(tasks != null && tasks.size() != 0, "tasks cannot be empty");

        IClientProfile profile = DefaultProfile
                .getProfile(contentScanProperties.getRegionId(), accessProperties.getAccessKeyId(), accessProperties.getAccessKeySecret());
        DefaultProfile
                .addEndpoint(contentScanProperties.getRegionId(), "Green", contentScanProperties.getGreenEndpoint());
        IAcsClient client = new DefaultAcsClient(profile);
        TextScanRequest textScanRequest = new TextScanRequest();
        textScanRequest.setAcceptFormat(FormatType.JSON); // 指定API返回格式。
        textScanRequest.setHttpContentType(FormatType.JSON);
        textScanRequest.setMethod(com.aliyuncs.http.MethodType.POST); // 指定请求方法。
        textScanRequest.setEncoding("UTF-8");
        textScanRequest.setRegionId(contentScanProperties.getRegionId());

        JSONObject data = new JSONObject();
        // 检测场景。文本垃圾检测请传递antispam。
        data.put("scenes", Arrays.asList("antispam"));
        data.put("bizType", "default");
        data.put("tasks", tasks);

        try {
            textScanRequest.setHttpContent(data.toJSONString().getBytes("UTF-8"), "UTF-8", FormatType.JSON);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }

        // 请务必设置超时时间。
        textScanRequest.setConnectTimeout(3000);
        textScanRequest.setReadTimeout(6000);

        try {
            HttpResponse httpResponse = client.doAction(textScanRequest);
            if(httpResponse.isSuccess()){
                JSONObject scrResponse = JSON.parseObject(new String(httpResponse.getHttpContent(), "UTF-8"));

                if (200 == scrResponse.getInteger("code")) {
                    JSONArray taskResults = scrResponse.getJSONArray("data");
                    String dataId = scrResponse.getString("dataId");

                    for (Object taskResult : taskResults) {
                        if(200 == ((JSONObject)taskResult).getInteger("code")){
                            JSONArray sceneResults = ((JSONObject)taskResult).getJSONArray("results");
                            for (Object sceneResult : sceneResults) {
                                String scene = ((JSONObject)sceneResult).getString("scene");
                                String suggestion = ((JSONObject)sceneResult).getString("suggestion");
                                //根据scene和suggetion做相关处理。
                                //suggestion == pass表示未命中垃圾。suggestion == block表示命中了垃圾，可以通过label字段查看命中的垃圾分类。
                                boolean pass = "pass".equals(suggestion);

                                if (!pass) {
                                    log.warn("textScan return block {}", JSON.toJSONString(scrResponse, true));
                                }

                                afterScan.doAction(dataId, pass);

                            }
                        }else{
                            log.error("task process fail:" + ((JSONObject)taskResult).getInteger("code"));
                        }
                    }
                } else {
                    log.error("detect not success. code:" + scrResponse.getInteger("code"));
                }
            }else{
                log.error("response not success. status:" + httpResponse.getStatus());
            }

        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    @Override
    public void imageSyncScan(List<ImageTaskDTO> imageTaskDTOs, AfterScan afterScan) {
        IClientProfile profile = DefaultProfile
                .getProfile(contentScanProperties.getRegionId(), accessProperties.getAccessKeyId(), accessProperties.getAccessKeySecret());
        DefaultProfile
                .addEndpoint(contentScanProperties.getRegionId(), "Green", contentScanProperties.getGreenEndpoint());
        IAcsClient client = new DefaultAcsClient(profile);

        ImageSyncScanRequest imageSyncScanRequest = new ImageSyncScanRequest();
        // 指定API返回格式。
        imageSyncScanRequest.setAcceptFormat(FormatType.JSON);
        // 指定请求方法。
        imageSyncScanRequest.setMethod(MethodType.POST);
        imageSyncScanRequest.setEncoding("utf-8");
        //支持HTTP和HTTPS。
        imageSyncScanRequest.setProtocol(ProtocolType.HTTP);


        JSONObject httpBody = new JSONObject();
        /**
         * 设置要检测的风险场景。计费依据此处传递的场景计算。
         * 一次请求中可以同时检测多张图片，每张图片可以同时检测多个风险场景，计费按照场景计算。
         * 例如：检测2张图片，场景传递porn和terrorism，计费会按照2张图片鉴黄，2张图片暴恐检测计算。
         * porn：表示鉴黄场景。
         */
        httpBody.put("scenes", Arrays.asList("porn"));

        /**
         * 设置待检测图片。一张图片对应一个task。
         * 多张图片同时检测时，处理的时间由最后一个处理完的图片决定。
         * 通常情况下批量检测的平均响应时间比单张检测的要长。一次批量提交的图片数越多，响应时间被拉长的概率越高。
         * 这里以单张图片检测作为示例, 如果是批量图片检测，请自行构建多个task。
         */
        httpBody.put("tasks", imageTaskDTOs);

        imageSyncScanRequest.setHttpContent(org.apache.commons.codec.binary.StringUtils.getBytesUtf8(httpBody.toJSONString()),
                "UTF-8", FormatType.JSON);

        /**
         * 请设置超时时间。服务端全链路处理超时时间为10秒，请做相应设置。
         * 如果您设置的ReadTimeout小于服务端处理的时间，程序中会获得一个read timeout异常。
         */
        imageSyncScanRequest.setConnectTimeout(3000);
        imageSyncScanRequest.setReadTimeout(10000);
        HttpResponse httpResponse = null;
        try {
            httpResponse = client.doAction(imageSyncScanRequest);
        } catch (Exception e) {
            e.printStackTrace();
        }

        //服务端接收到请求，完成处理后返回的结果。
        if (httpResponse != null && httpResponse.isSuccess()) {
            JSONObject scrResponse = JSON.parseObject(org.apache.commons.codec.binary.StringUtils.newStringUtf8(httpResponse.getHttpContent()));
//            System.out.println(JSON.toJSONString(scrResponse, true));
            int requestCode = scrResponse.getIntValue("code");
            //每一张图片的检测结果。
            JSONArray taskResults = scrResponse.getJSONArray("data");
            if (200 == requestCode) {
                String dataId = scrResponse.getString("dataId");

                for (Object taskResult : taskResults) {
                    //单张图片的处理结果。
                    int taskCode = ((JSONObject) taskResult).getIntValue("code");
                    //图片对应检测场景的处理结果。如果是多个场景，则会有每个场景的结果。
                    JSONArray sceneResults = ((JSONObject) taskResult).getJSONArray("results");
                    if (200 == taskCode) {
                        for (Object sceneResult : sceneResults) {
                            String scene = ((JSONObject) sceneResult).getString("scene");
                            String suggestion = ((JSONObject) sceneResult).getString("suggestion");
                            //根据scene和suggetion做相关处理。
                            //do something
//                            System.out.println("scene = [" + scene + "]");
//                            System.out.println("suggestion = [" + suggestion + "]");

                            boolean pass = "pass".equals(suggestion);

                            if (!pass) {
                                log.warn("imageScan return {}", JSON.toJSONString(scrResponse, true));
                            }

                            afterScan.doAction(dataId, pass);

                        }
                    } else {
                        //单张图片处理失败, 原因视具体的情况详细分析。
                        log.error("task process fail. task response:" + JSON.toJSONString(taskResult));
                    }
                }
            } else {
                /**
                 * 表明请求整体处理失败，原因视具体的情况详细分析。
                 */
                log.error("the whole image scan request failed. response:" + JSON.toJSONString(scrResponse));
            }
        }

    }

    @Override
    public JSONArray videoAsyncScan(List<VideoTaskDTO> videoTaskDTOs) {
        // 正确返回格式 {"msg":"OK","code":200,"dataId":"a0f333bc-c0b8-4470-8b3a-365581cb7699","taskId":"vi5KcvbbjQQ$R7VLvyJbsFbZ-1trPXp","url":"https://v-cdn.zjol.com.cn/280443.mp4"}
        IClientProfile profile = DefaultProfile
                .getProfile(contentScanProperties.getRegionId(), accessProperties.getAccessKeyId(), accessProperties.getAccessKeySecret());
        DefaultProfile
                .addEndpoint(contentScanProperties.getRegionId(), "Green", contentScanProperties.getGreenEndpoint());
        IAcsClient client = new DefaultAcsClient(profile);

        VideoAsyncScanRequest videoAsyncScanRequest = new VideoAsyncScanRequest();
        videoAsyncScanRequest.setAcceptFormat(FormatType.JSON); // 指定API返回格式。
        videoAsyncScanRequest.setMethod(com.aliyuncs.http.MethodType.POST); // 指定请求方法。

        /**
         * 设置要检测的场景。计费是依据此处传递的场景计算。
         * 视频默认1秒截取一帧，您可以自行控制截帧频率。收费按照视频的截帧数量以及每一帧的检测场景计算。
         * 举例：1分钟的视频截帧60张，检测色情（对应场景参数porn）和暴恐涉政（对应场景参数terrorism）2个场景，收费按照60张色情+60张暴恐涉政进行计费。
         */
        JSONObject data = new JSONObject();
        data.put("scenes", Arrays.asList("porn", "terrorism"));
        data.put("tasks", videoTaskDTOs);
//        data.put("callback", "http://xxx.xxx.xx/xxx.json");
//        data.put("seed", "yourPersonalSeed");

        videoAsyncScanRequest.setHttpContent(data.toJSONString().getBytes(StandardCharsets.UTF_8), "UTF-8", FormatType.JSON);

        /**
         * 请务必设置超时时间。
         */
        videoAsyncScanRequest.setConnectTimeout(3000);
        videoAsyncScanRequest.setReadTimeout(6000);
        try {
            HttpResponse httpResponse = client.doAction(videoAsyncScanRequest);

            if(httpResponse.isSuccess()){
                JSONObject jsonObject = JSON.parseObject(httpResponse.getHttpContentString());
                System.out.println(JSON.toJSONString(jsonObject, true));
                return jsonObject.getJSONArray("data");
            }else{
                log.error("response not success. status:" + httpResponse.getStatus());
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return null;
    }

    @Override
    public List<AsyncScanResult> queryVideoAsyncScanResult(List<String> taskIds) {
        IClientProfile profile = DefaultProfile
                .getProfile(contentScanProperties.getRegionId(), accessProperties.getAccessKeyId(), accessProperties.getAccessKeySecret());
        DefaultProfile
                .addEndpoint(contentScanProperties.getRegionId(), "Green", contentScanProperties.getGreenEndpoint());
        IAcsClient client = new DefaultAcsClient(profile);

        VideoAsyncScanResultsRequest videoAsyncScanResultsRequest = new VideoAsyncScanResultsRequest();
        videoAsyncScanResultsRequest.setAcceptFormat(FormatType.JSON);

        videoAsyncScanResultsRequest.setHttpContent(JSON.toJSONString(taskIds).getBytes(StandardCharsets.UTF_8), "UTF-8", FormatType.JSON);

        /**
         * 请务必设置超时时间。
         */
        videoAsyncScanResultsRequest.setConnectTimeout(3000);
        videoAsyncScanResultsRequest.setReadTimeout(6000);
        try {
            HttpResponse httpResponse = client.doAction(videoAsyncScanResultsRequest);
            if(httpResponse.isSuccess()){
                JSONObject jsonObject = JSON
                        .parseObject(httpResponse.getHttpContentString());
                System.out.println(JSON.toJSONString(jsonObject, true));

                JSONArray datas = jsonObject.getJSONArray("data");

                List<AsyncScanResult> asyncScanResults = new ArrayList<>();

                for (int i = 0; i < datas.size(); i++) {
                    JSONObject d = datas.getJSONObject(i);
                    Integer code = d.getInteger("code");
                    String taskId = d.getString("taskId");

                    if (code != 200) {
                        AsyncScanResult resultVO = new AsyncScanResult();
                        resultVO.setTaskId(taskId);
                        resultVO.setPass(false);
                        resultVO.setDone(false);
                        asyncScanResults.add(resultVO);

                    } else {
                        AsyncScanResult resultVO = new AsyncScanResult();
                        resultVO.setTaskId(taskId);
                        resultVO.setPass(true);
                        resultVO.setDone(true);

                        JSONArray results = d.getJSONArray("results");

                        for (int j = 0; j < results.size(); j++) {
                            JSONObject r = results.getJSONObject(j);
                            String suggestion = r.getString("suggestion");
                            if (!"pass".equals(suggestion)) {
                                resultVO.setPass(false);
                                break;
                            }

                        }

                        asyncScanResults.add(resultVO);

                    }

                    return asyncScanResults;

                }

            }else{
                log.error("response not success. status:" + httpResponse.getStatus());
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }
}
